﻿#pragma warning disable 1591

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace TotalFreedomKO
{
    public interface IHtmlElement : IHtmlString
    {
    }

    public interface IHtmlSrcElement
    {
    }

    public interface IHtmlContainer : IHtmlElement
    {
        IHtmlContainer Add(IHtmlElement element);
        IHtmlContainer Add(string text, object htmlAttributes = null);
        IHtmlContainer Add<E>(string value = null, object htmlAttributes = null) where E : IHtmlElement;
    }

    public class HtmlContainer<T> : IHtmlContainer where T : IHtmlContainer
    {
        private HtmlHelper _htmlHelper;

        public string InnerText { get; set; }
        public RouteValueDictionary HtmlAttributes { get; set; }

        private List<IHtmlElement> _attachedElements;

        public HtmlContainer(HtmlHelper htmlHelper, string value = null, RouteValueDictionary htmlAttributes = null)
        {
            _htmlHelper = htmlHelper;
            InnerText = value;
            HtmlAttributes = htmlAttributes;
        }

        public string ToHtmlString()
        {
            Type t = typeof(T);
            bool isSimpleContainer = typeof(SimpleContainer) == t;

            StringBuilder sb = new StringBuilder();
            if (!isSimpleContainer)
                sb.Append("<" + t.Name.ToLower() + ">");

            if(!String.IsNullOrEmpty(InnerText))
                sb.Append(HttpUtility.HtmlEncode(InnerText));

            if (_attachedElements != null)
            {
                foreach (IHtmlElement element in _attachedElements)
                {
                    sb.Append(element.ToHtmlString());
                }
            }

            if (!isSimpleContainer)
                sb.Append("</" + t.Name.ToLower() + ">");

            return sb.ToString();
        }

        public IHtmlContainer Add(IHtmlElement element)
        {
            if (_attachedElements == null)
                _attachedElements = new List<IHtmlElement>();

            _attachedElements.Add(element);

            return this;
        }

        public IHtmlContainer Add(string text, object htmlAttributes = null)
        {
            if (_attachedElements == null)
                _attachedElements = new List<IHtmlElement>();

            RouteValueDictionary attrs = null;
            if (htmlAttributes != null)
                attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

            if (attrs != null)
                _attachedElements.Add(new HtmlElement<Span>(text, attrs));
            else
                _attachedElements.Add(new HtmlElement<SimpleText>(text));

            return this;
        }

        public IHtmlContainer Add<E>(string value = null, object htmlAttributes = null) where E : IHtmlElement
        {
            RouteValueDictionary attrs = null;
            if (htmlAttributes != null)
                attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

            Type t = typeof(E);
            if (typeof(IHtmlSrcElement).IsAssignableFrom(t))
            {
                var url = new UrlHelper(_htmlHelper.ViewContext.RequestContext);
                value = url.Content(value);
            }

            HtmlElement<E> element = new HtmlElement<E>(value, attrs);
            return Add(element);
        }
    }

    public class HtmlElement<T> : IHtmlElement where T : IHtmlElement
    {
        public string Src { get; set; }
        public string InnerText { get; set; }
        public RouteValueDictionary HtmlAttributes { get; set; }

        public HtmlElement(string value = null, RouteValueDictionary htmlAttributes = null)
        {
            HtmlAttributes = htmlAttributes;

            Type t = typeof(T);

            if (typeof(IHtmlSrcElement).IsAssignableFrom(t))
                Src = value;
            else
                InnerText = value;
        }

        public string ToHtmlString()
        {
            Type t = typeof(T);
            bool isSimpleText = typeof(SimpleText) == t;

            string s = "";
            if (!isSimpleText)
            {
                s += "<" + t.Name.ToLower();
                if (!String.IsNullOrEmpty(Src))
                    s += " src=\"" + HttpUtility.HtmlAttributeEncode(Src) + "\"";

                s += KoHtml.HtmlFromAttributes(HtmlAttributes) + ">";
            }

            s += HttpUtility.HtmlEncode(InnerText);

            if (!isSimpleText)
                s += "</" + t.Name.ToLower() + ">";

            return s;
        }
    }

    public static class HtmlAttrs
    {
        public static object CssClass(string className) 
        {
            return new { @class = className };
        }

        public static object CssStyle(string style)
        {
            return new { style = style };
        }

        public static object Id(string id)
        {
            return new { id = id };
        }
    }


    public static class KoHtml
    {
        #region HTML helpers

        public static string AttributeOrDefault(RouteValueDictionary attrs, string attributeName, string defaultValue)
        {
            string result = defaultValue;
            if (attrs != null && attrs.ContainsKey(attributeName))
            {
                object v = attrs[attributeName];
                if (v != null)
                    result = v.ToString();
            }

            if (result == null)
                return "";
            else
                return " " + attributeName + "=\"" + HttpUtility.HtmlAttributeEncode(result) + "\"";
        }

        public static string ValuePlusAttribute(string attributeName, string value, RouteValueDictionary attrs)
        {
            string result = "";
            if (attrs != null && attrs.ContainsKey(attributeName))
            {
                object v = attrs[attributeName];
                if (v != null)
                    result = " " + v.ToString();
            }

            return " " + attributeName + "=\"" + HttpUtility.HtmlAttributeEncode(value) + HttpUtility.HtmlAttributeEncode(result) + "\"";
        }

        public static string HtmlFromAttributes(RouteValueDictionary attrs, string[] exceptAttrs = null)
        {
            string s = "";

            if (attrs != null)
            {
                IEnumerable<string> keys = exceptAttrs == null ? attrs.Keys : attrs.Keys.Where(w => exceptAttrs == null || !exceptAttrs.Contains(w));
                foreach (string key in keys)
                {
                    object value = attrs[key];
                    if (value != null)
                        s += " " + key + "=\"" + HttpUtility.HtmlAttributeEncode(value.ToString()) + "\"";
                }
            }

            return s;
        }

        public static IHtmlContainer Container(HtmlHelper htmlHelper, string content = null, object htmlAttributes = null)
        {
            RouteValueDictionary attrs = null;
            if (htmlAttributes != null)
                attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

            HtmlContainer<SimpleContainer> container = new HtmlContainer<SimpleContainer>(htmlHelper, content, attrs);

            return container;
        }

        public static IHtmlContainer Container<T>(HtmlHelper htmlHelper, string content = null, object htmlAttributes = null) where T : IHtmlContainer
        {
            RouteValueDictionary attrs = null;
            if (htmlAttributes != null)
                attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

            HtmlContainer<T> container = new HtmlContainer<T>(htmlHelper, content, attrs);

            return container;
        }

        public static IHtmlElement Element<T>(HtmlHelper htmlHelper, string content, object htmlAttributes = null) where T : IHtmlElement
        {
            RouteValueDictionary attrs = null;
            if (htmlAttributes != null)
                attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

            Type t = typeof(T);
            if (typeof(IHtmlSrcElement).IsAssignableFrom(t))
            {
                var url = new UrlHelper(htmlHelper.ViewContext.RequestContext);
                content = url.Content(content);
            }

            HtmlElement<T> element = new HtmlElement<T>(content, attrs);

            return element;
        }

        #endregion
    }

    #region html tags

    public interface SimpleContainer : IHtmlContainer { }
    public interface Div : IHtmlContainer { }
    public interface P : IHtmlContainer { }
    public interface UL : IHtmlContainer { }
    public interface OL : IHtmlContainer { }
    public interface Span : IHtmlElement { }
    public interface SimpleText : IHtmlElement { }
    public interface H1 : IHtmlElement { }
    public interface H2 : IHtmlElement { }
    public interface H3 : IHtmlElement { }
    public interface H4 : IHtmlElement { }
    public interface H5 : IHtmlElement { }
    public interface LI : IHtmlElement { }
    public interface A : IHtmlElement { }
    public interface Label : IHtmlElement { }
    public interface Img : IHtmlElement, IHtmlSrcElement { }

    #endregion
}
